package parser

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"text/template"

	"github.com/360EntSecGroup-Skylar/excelize"
)

// 单表解析
func StructSheetParseClient(rows [][]string, sheet string) *StructDesc {

	columnNum := len(rows[0])

	// 元数据列表
	metaList := make([]*DataMeta, columnNum)

	// 前4行结构定义
	for j := 1; j < columnNum; j++ {

		if rows[3][j] == "END" {
			break
		}

		meta := &DataMeta{
			// NameType: rows[0][j],
			DataType: rows[2][j],
			Name:     rows[1][j],
			Comment:  rows[0][j],
		}

		metaList[j] = meta
	}

	// 结构体描述
	desc := StructDescParse(metaList, sheet)

	return desc
}

func StructParseSysLang(sheetSlice []string, xlsx *excelize.File) (ret string) {
	sdlist := []*StructDesc{}
	sdlistClient := []*StructDesc{}
	for _, sheet := range sheetSlice {
		rows := xlsx.GetRows(sheet)
		if len(rows) <= 0 {
			ret = fmt.Sprintf("[StructParse:sheet:%v] 表不存在或者为空 len(rows):%v", sheet, len(rows))
			return
		}
		desc := StructSheetParse(rows, clientPkg) //StructSheetParse(rows, sheet)
		sdlist = append(sdlist, desc)

		descClient := StructSheetParseClient(rows, clientPkg) //StructSheetParseClient(rows, sheet)
		sdlistClient = append(sdlistClient, descClient)

	}

	for _, name := range serverFiles {
		outFilename := fmt.Sprintf("%s\\%s.go", codeOutputPath+name, strings.ToLower(pkg))

		outFile, err := os.Create(outFilename)
		defer outFile.Close()
		if err != nil {
			return err.Error()
		}

		tmpl, err := template.New("struct_gen").Funcs(funcMap).Parse(tpl)
		if err != nil {
			return err.Error()
		}
		sdOnlyOnelist := []*StructDesc{}
		for _, d := range sdlist {
			sdOnlyOnelist = append(sdOnlyOnelist, d)
			break
		}
		err = tmpl.Execute(outFile, &StructPkg{PkgName: name, Name: strings.ToLower(pkg), List: sdOnlyOnelist})
		if err != nil {
			return err.Error()
		}
	}

	// 客户端代码
	var nick string
	if clientNick != "" {
		clientFiles = append(clientFiles, "Hotfix")
		clientFiles = append(clientFiles, "Main")
	}
	if clientNick == "clientHclientM" {
		clientNick = "AppType.ClientH | AppType.ClientM"
		nick = "AppType.ClientH | AppType.ClientM"
	} else if strings.Contains(clientNick, "clientH") {
		nick = "AppType.ClientH"
	} else if strings.Contains(clientNick, "clientM") {
		nick = "AppType.ClientM"
	}
	fmt.Println("clientNick:", clientNick)
	fmt.Println("nick:", nick)
	for _, name := range clientFiles {

		clientNameSpace := "ETModel"
		if name == "Hotfix" {
			clientNameSpace = "ETHotfix"
		}

		outFilename := fmt.Sprintf("%s\\%s.cs", clientCodeOutputPath+name, "T"+clientPkg+"AVO")

		outFile, err := os.Create(outFilename)
		defer outFile.Close()
		if err != nil {
			return err.Error()
		}

		tmpl, err := template.New("struct_gen").Funcs(funcMap).Parse(cstplH)
		if err != nil {
			return err.Error()
		}
		sdOnlyOnelist := []*StructDesc{}
		for _, d := range sdlistClient {
			sdOnlyOnelist = append(sdOnlyOnelist, d)
			break
		}
		err = tmpl.Execute(outFile, &StructPkg{Name: clientPkg, ClientNameSpace: clientNameSpace, ClientNick: nick, List: sdOnlyOnelist})
		if err != nil {
			return err.Error()
		}

	}

	return

}

type Smap []*SortMapNode

type SortMapNode struct {
	Key string
	Val interface{}
}

func (c *Smap) Put(key string, val interface{}) {
	index, _, ok := c.get(key)
	if ok {
		(*c)[index].Val = val
	} else {
		node := &SortMapNode{Key: key, Val: val}
		*c = append(*c, node)
	}
}

func (c *Smap) Get(key string) (interface{}, bool) {
	_, val, ok := c.get(key)
	return val, ok
}

func (c *Smap) get(key string) (int, interface{}, bool) {
	for index, node := range *c {
		if node.Key == key {
			return index, node.Val, true
		}
	}
	return -1, nil, false
}

func ToSortedMapJson(smap *Smap) string {
	s := "{"
	for _, node := range *smap {
		v := node.Val
		isSamp := false
		str := ""
		switch v.(type) {
		case *Smap:
			isSamp = true
			str = ToSortedMapJson(v.(*Smap))
		}

		if !isSamp {
			b, _ := json.Marshal(node.Val)
			str = string(b)
		}

		s = fmt.Sprintf("%s\"%s\":%s,", s, node.Key, str)
	}
	s = strings.TrimRight(s, ",")
	s = fmt.Sprintf("%s}", s)
	return s
}
